/**
 * 获取数组最大值
 * @param {Array} arr => 数组 
 */
function getMax(arr) {
    return Math.max.apply(null, arr)
}

/**
 * 获取数组最小值
 * @param {Array} arr => 数组 
 */
function getMin(arr) {
    return Math.min.apply(null, arr)
}

/**
 * 冒泡排序
 * @param {Array} arr => 数组
 */
function bubbleSort(arr) {
    for (let i = 0; i < arr.length; i++) {
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[i] > arr[j]) {
                var temp = arr[i]
                arr[i] = arr[j]
                arr[j] = temp
            }
        }
    }
}

/**
 * 快速排序
 * @param {Array} arr => 数组 
 */
function quickSort(arr) {
    if (arr.length <= 1) {
        return arr
    }
    var pivotIndex = Math.floor(arr.length / 2)
    var pivot = arr.splice(pivotIndex, 1)[0]
    var left = []
    var right = []
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i])
        } else {
            right.push(arr[i])
        }
    }
    return quickSort(left).concat([pivot], quickSort(right))
}

function quickSort(a) {
    return a.length <= 1 ? a : quickSort(a.slice(1).filter(item => item <= a[0])).concat(a[0], quickSort(a.slice(1).filter(item => item > a[0])))
}


/**
 * 数组去重
 * @param {Array} arr => 数组
 */
function delRepeat(arr) {
    var res = []
    var n = {}
    for (var i = 0; i < arr.length; i++) {
        if (!n[arr[i]]) {
            n[arr[i]] = true
            res.push(arr[i])
        }
    }
    return res
}

/**
 * 统计重复次数和值
 * @param {Array} arr => 数组
 */
function countNum(arr) {
    var max = 0
    var value = []
    var obj = arr.reduce(function (obj, key) {
        key in obj ? obj[key]++ : (obj[key] = 1)
        return obj
    }, {})
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            max = Math.max(max, obj[key])
        }
    }
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            if (obj[key] == max) {
                value.push(key)
            }
        }
    }
    return {
        max,
        value
    }
}

/**
 * 统计重复次数和值(map实现版,避免了obj键为字符串的尴尬)
 * @param {Array} arr => 数组
 */
function countNum(arr) {
    var map = arr.reduce(function (m, x) {
        return m.set(x, (m.get(x) || 0) + 1)
    }, new Map())

    var res = []
    var value = [];
    for (let [k, v] of map) {
        res.push(v)
    }
    for (let [k, v] of map) {
        if (map.get(k) == _.getMax(res)) {
            value.push(k)
        }
    }
    return {
        max: _.getMax(res),
        value: value
    }
}

/**
 * 排序数组里的对象(集合)的某个字段排序
 * @param {Array} arr => 数组
 * @param {String} key => 字段名
 */
function sortObj(arr, key) {
    arr.sort(function (m, n) {
        var key1 = m[key]
        var key2 = n[key]
        return key2 - key1
    })
}

/**
 * 查找集合的数据
 * @param {Array} arr => 数组
 * @param {Object} obj => 要查找的对象
 */
function where(arr, obj) {
    var index = []
    var keys = Object.keys(obj)
    for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < keys.length; j++) {
            if (arr[i][keys[j]] !== obj[keys[j]]) {
                index.push(i)
                break
            }
        }
    }
    var k = 0
    for (let i = 0; i < index.length; i++) {
        arr.splice(index[i] - k, 1)
        k++
    }
    return arr
}

/**
 * 随机生成指定数字的数组，如不指定则生成一个数
 * @param {Array} arr => 数组
 * @param {Number} num => 个数（可选）
 */
function sample(arr, num) {
    if (num == 1 || num == undefined) {
        return arr.sort(() => {
            Math.random() - 0.5
        }).splice(0, 1)
    }
    return arr.sort(() => {
        Math.random() - 0.5
    }).splice(0, num)
}
/**
 * 获得集合中最近的点
 * @param {Array} arr => 数组
 * @param {Object} obj => 你传入的点的位置
 */
function getMinDistance(arr, obj) {
    var result = {
        index: 0
    }
    for (var i = 0; i < arr.length; i++) {
        var x = Math.abs(arr[i].x - obj.x)
        var y = Math.abs(arr[i].y - obj.y)
        var temp = x + y
        if (i == 0) {
            result.index = i
            result.y = temp
        } else {
            if (result.y > temp) {
                result.index = i
                result.y = temp
            }
        }
    }
    return {
        x: arr[result.index].x,
        y: arr[result.index].y
    }
}


/**
 * 根据提供的规则分组
 * @param {Array} arr => 数组
 * @param {String/Function} rule => 规则 
 */
function groupBy(arr, rule) {
    if (rule === "length") {
        var obj = arr.reduce((obj, key) => {
            key.length in obj ? obj[key.length].push(key) : (obj[key.length] = [key])
            return obj
        }, {})
    } else {
        var obj = arr.reduce(function (obj, num) {
            var key = rule(num);
            key in obj ? obj[key].push(num) : (obj[key] = [num])
            return obj
        }, {})
    }
    return obj;
}

/**
 * 返回集合中某属性值，返回一个数组
 * @param {Array} arr => 数组 
 * @param {key} key => 集合的key值
 */
function pluck(arr, key) {
    var res = []
    if (!arr[0].hasOwnProperty(key)) return;
    for (let i = 0; i < arr.length; i++) {
        res.push(arr[i][key])
    }
    return res
}

/**
 * 多维数组变成一维数组
 * @param {Array} arr => 数组
 * @param {Boolean} shallow => 数组将只减少一维的嵌套
 */
function flatten(arr, shallow) {
    if (shallow) {
        var arr = arr.reduce((arr, val) => arr.concat(val), [])
    } else {
        var arr = arr.reduce((arr, val) => arr.concat(Array.isArray(val) ? flatten(val) : val), [])
    }
    return arr
}



/**
 * 返回一个删除所有values值后的 array副本
 * @param {Arrar} arr => 数组
 * @param {argument} arg => 任意参数 
 */
function without(arr, ...arg) {
    return difference(arr, arg)
}

/**
 * 返回两个数组的交集
 * @param {Array} arr1 => 数组
 * @param {Array} arr2 => 数组
 */
function intersection(arr1, arr2) {
    return arr1.filter(v => arr2.includes(v))
}
/**
 * 返回多个数组的交集
 * @param {Array} arr1 => 数组
 * @param {argument} arg => 任意数组
 */
function intersectionMore(arr1, ...arg) {
    return arg.length <= 1 ? arr1.filter(v => arg[0].includes(v)) : intersection(arr1.filter(v => arg[0].includes(
        v)), ...arg.slice(1));
}


/**
 * 返回两个数组的不同的数
 * @param {Array} arr1 => 数组
 * @param {Array} arr2 => 数组
 */
function difference(arr1, arr2) {
    return arr1.concat(arr2).filter(v => !arr1.includes(v) || !arr2.includes(v));
}

/**
 * 返回多个数组的不同的数
 * @param {Array} arr1 => 数组
 * @param {argument} arg => 数组
 */
function differenceMore(arr1, ...arg) {
    return difference(arr1, flatten(arg, true))
}
/**
 * 返回一个过滤值后的新数组(根据arr1来排除)
 * @param {Array} arr1 => 数组
 * @param {argument} arg => 排除的值(数组)
 */
function exclude(arr1, ...arg) {
    return arr1.filter(v => !arr1.includes(v) || !flatten(arg, true).includes(v))
}
/**
 * 根据所提供的规则的key,返回key最大的值所在的字段(数组)
 * @param {Array} arr => 数组
 * @param {Function} rule => 规则
 */
function max(arr, rule) {
    var num = []
    for (let i = 0; i < arr.length; i++) {
        num.push(rule(arr[i]))
    }
    var max = getMax(num)
    var res = arr.filter(currentValue => {
        return currentValue.age >= max
    })
    return res
}

/**
 * 返回乱序的数组
 * @param {Array} arr => 数组 
 */
function shuffle(arr) {
    return arr.sort(function () {
        return Math.random() - 0.5
    })
}


/**
 * 返回一个根据subArrayNum的二维数组
 * @param {Array} arr => 一维数组
 * @param {Number} subArrayNum => 每组元素的个数
 */
function getMatrix(arr, subArrayNum) {
    var res = new Array(Math.ceil(arr.length / subArrayNum));
    for (let i = 0; i < res.length; i++) {
        res[i] = new Array();
        for (let j = 0; j < i % subArrayNum; j++) {
            res[i][j] = '';
        }
    }
    for (let i = 0; i < arr.length; i++) {
        res[parseInt(i / subArrayNum)][i % subArrayNum] = arr[i];
    }
    return res;
}


/**
 * 根据所提供的字符分组
 * @param {Array} arr => 数组
 * @param {String} key => 需要分组的字段 
 */
function keyBy(arr, key) {
    return arr.reduce(function (newObj, obj) {
        if (!newObj[obj[key]]) {
            newObj[obj[key]] = [];
            newObj[obj[key]].push(obj);
        } else {
            newObj[obj[key]].push(obj);
        }
        return newObj;
    }, {});
}